package com.yfm.RpcServer;


import com.yfm.Bean.RpcRequest;
import com.yfm.Bean.RpcResponse;
import com.yfm.RegistryInterface;
import com.yfm.RegistryService;
import com.yfm.codec.RpcDecoder;
import com.yfm.codec.RpcEncoder;
import com.yfm.registry.ServiceRegistry;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

@Component
public class RpcServer implements ApplicationContextAware, InitializingBean {

  //  private static final Logger LOGGER = LoggerFactory.getLogger(RpcServer.class);

    private String serviceAddress = "127.0.0.1:8081";

    @Autowired
    private RegistryInterface registryInterface;



    /**
     * 存放 服务名 与 服务对象 之间的映射关系
     */
    private Map<String, Object> handlerMap = new HashMap<>();

    /**
     * 通过实现ApplicationContextAware接口中的setApplicationContext方法，
     * 我们可以获取到spring操作applicationContext变量，
     * 就是操作注入的bean
     * @param ctx
     * @throws BeansException
     */

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        // 扫描带有 RpcService 注解的类并初始化 handlerMap 对象
        Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class);
        if ( serviceBeanMap!=null && serviceBeanMap.size()>0 ) {
            for (Object serviceBean : serviceBeanMap.values()) {
                RpcService rpcService = serviceBean.getClass().getAnnotation(RpcService.class);
                String serviceName = rpcService.value().getName();
                String serviceVersion = rpcService.version();
                if (serviceVersion!=null && !serviceVersion.isEmpty()) {
                    serviceName += "-" + serviceVersion;
                }
                handlerMap.put(serviceName, serviceBean);
            }
        }
    }

    /**
     * InitializingBean
     * Bean初始化时执行的操作
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class) //使用NIO模式
                    .childHandler(new ChannelInitializer<SocketChannel>() {


                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            pipeline.addLast(new RpcDecoder(RpcRequest.class));// 解码RPC请求
                            pipeline.addLast(new RpcEncoder(RpcResponse.class));// 编码RPC响应
                            pipeline.addLast(new RpcServerHandle(handlerMap)); //接收的请求 处理的实现
                        }
                    }); //初始化器为HttpServerInitializer

            bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            //注册到zk
           for (String i : handlerMap.keySet()){
               registryInterface.registry(i,serviceAddress);
               System.out.println("registry name: "+i+"  node: "+serviceAddress);
           }


           //解析 ip  port

            String[] str = serviceAddress.split(":");
            String ip = str[0];
            int port = Integer.parseInt(str[1]);

            //开启服务器
            ChannelFuture  f = bootstrap.bind(ip,port).sync();
            System.out.println("开启");
            //关闭服务器
            f.channel().closeFuture().sync();
            System.out.println("关闭");


        }catch (Exception e){
            e.printStackTrace();
        }finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }


    }
}
